package common

import (
	"fmt"
	"os"
	"path/filepath"
	"sync"
	"time"
)

type LogLevel int

const (
	LogDebug LogLevel = iota
	LogInfo
	LogWarn
	LogError
)

const (
	LogTypeMain     = "main"     // 主日志
	LogTypeError    = "error"    // 错误日志
	LogTypeAccess   = "access"   // 访问日志
	LogTypeTransfer = "transfer" // 传输日志
	LogTypeSecurity = "security" // 安全日志
)

type LogEntry struct {
	Time    time.Time
	Level   LogLevel
	Message string
}

// LogConfig 日志配置
type LogConfig struct {
	ConsoleLevel  string    `json:"console_level"`
	FileLogs      []FileLog `json:"file_logs"`
	RetentionDays int       `json:"retention_days"`
}

// FileLog 文件日志配置
type FileLog struct {
	Type    string `json:"type"`
	Path    string `json:"path"`
	MaxSize int64  `json:"max_size"`
}

type LogManager struct {
	file        *os.File
	mu          sync.Mutex
	logLevel    LogLevel
	maxSize     int64
	baseDir     string
	currentSize int64
	logType     string // 日志类型
	config      *LogConfig
}

func NewLogManager(config *LogConfig, logType string) (*LogManager, error) {
	// 查找对应类型的配置
	var fileLog FileLog
	for _, log := range config.FileLogs {
		if log.Type == logType {
			fileLog = log
			break
		}
	}

	if fileLog.Type == "" {
		return nil, fmt.Errorf("未找到日志类型 %s 的配置", logType)
	}

	lm := &LogManager{
		logLevel: getLogLevelFromString(config.ConsoleLevel),
		maxSize:  fileLog.MaxSize,
		baseDir:  fileLog.Path,
		logType:  logType,
		config:   config,
	}

	if err := os.MkdirAll(fileLog.Path, 0755); err != nil {
		return nil, err
	}

	if err := lm.rotate(); err != nil {
		return nil, err
	}

	go lm.cleanupRoutine()
	return lm, nil
}

func (lm *LogManager) Log(level LogLevel, format string, args ...interface{}) {
	if level < lm.logLevel {
		return
	}

	lm.mu.Lock()
	defer lm.mu.Unlock()

	entry := LogEntry{
		Time:    time.Now(),
		Level:   level,
		Message: fmt.Sprintf(format, args...),
	}

	logLine := fmt.Sprintf("[%s] [%s] %s\n",
		entry.Time.Format("2006-01-02 15:04:05.000"),
		levelToString(entry.Level),
		entry.Message,
	)

	n, err := lm.file.WriteString(logLine)
	if err != nil {
		fmt.Fprintf(os.Stderr, "写入日志失败: %v\n", err)
		return
	}

	lm.currentSize += int64(n)
	if lm.currentSize >= lm.maxSize {
		if err := lm.rotate(); err != nil {
			fmt.Fprintf(os.Stderr, "轮转日志失败: %v\n", err)
		}
	}
}

func (lm *LogManager) rotate() error {
	if lm.file != nil {
		lm.file.Close()
	}

	timestamp := time.Now().Format("20060102_150405")
	filename := fmt.Sprintf("log_%s.txt", timestamp)
	filepath := filepath.Join(lm.baseDir, filename)

	file, err := os.OpenFile(filepath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		return err
	}

	lm.file = file
	lm.currentSize = 0
	return nil
}

func levelToString(level LogLevel) string {
	switch level {
	case LogDebug:
		return "DEBUG"
	case LogInfo:
		return "INFO"
	case LogWarn:
		return "WARN"
	case LogError:
		return "ERROR"
	default:
		return "UNKNOWN"
	}
}

// 根据日志类型记录日志
func (lm *LogManager) LogWithType(level LogLevel, logType string, format string, args ...interface{}) {
	// 控制台只输出错误日志
	if level >= LogError {
		fmt.Printf("[%s] %s\n", levelToString(level), fmt.Sprintf(format, args...))
	}

	// 文件日志按配置记录
	if lm.logType == logType {
		lm.Log(level, format, args...)
	}
}

// 清理过期日志时考虑保留天数
func (lm *LogManager) cleanupRoutine() {
	ticker := time.NewTicker(24 * time.Hour)
	defer ticker.Stop()

	for range ticker.C {
		cutoff := time.Now().AddDate(0, 0, -lm.config.RetentionDays)
		lm.cleanup(cutoff)
	}
}

func getLogLevelFromString(level string) LogLevel {
	switch level {
	case "debug":
		return LogDebug
	case "info":
		return LogInfo
	case "warn":
		return LogWarn
	case "error":
		return LogError
	default:
		return LogError // 默认使用 error 级别
	}
}

func (lm *LogManager) cleanup(cutoff time.Time) {
	entries, err := os.ReadDir(lm.baseDir)
	if err != nil {
		fmt.Fprintf(os.Stderr, "读取日志目录失败: %v\n", err)
		return
	}

	for _, entry := range entries {
		if !entry.IsDir() {
			continue
		}

		// 解析目录名为日期
		dirDate, err := time.Parse("2006-01-02", entry.Name())
		if err != nil {
			continue
		}

		// 如果目录早于截止日期，删除它
		if dirDate.Before(cutoff) {
			dirPath := filepath.Join(lm.baseDir, entry.Name())
			if err := os.RemoveAll(dirPath); err != nil {
				fmt.Fprintf(os.Stderr, "删除旧日志目录失败 %s: %v\n", dirPath, err)
			}
		}
	}
}

// Cleanup 清理指定日期之前的日志
func (lm *LogManager) Cleanup(cutoff time.Time) error {
	lm.mu.Lock()
	defer lm.mu.Unlock()

	entries, err := os.ReadDir(lm.baseDir)
	if err != nil {
		return fmt.Errorf("读取日志目录失败: %v", err)
	}

	for _, entry := range entries {
		if !entry.IsDir() {
			continue
		}

		// 解析目录名为日期
		dirDate, err := time.Parse("2006-01-02", entry.Name())
		if err != nil {
			continue
		}

		// 如果目录早于截止日期，删除它
		if dirDate.Before(cutoff) {
			dirPath := filepath.Join(lm.baseDir, entry.Name())
			if err := os.RemoveAll(dirPath); err != nil {
				return fmt.Errorf("删除旧日志目录失败 %s: %v", dirPath, err)
			}
		}
	}
	return nil
}
